import React, {Component} from 'react';
import {
  View,
  Text,
  ScrollView,
  Platform,
  StyleSheet,
} from 'react-native';
import PropTypes from 'prop-types';


export default class Headline1 extends Component {

  static defaultProps = {
    headlineList: [{content: '第aaaaaaaaaaaaaaa'}, {content: '第23个'}, {content: '第34个'}, {content: '第99个'}],
    itemHeight:20,
  }

  render () {
    return (
      <View>
        <Headline
          autoplay={true}
          infinite={true}
          autoplayInterval={3000}
          itemHeight={this.props.itemHeight}
        >{
          this.props.headlineList.map((item, index) => {
            return (
              <View style={{backgroundColor: 'red',height:this.props.itemHeight}}>
                <Text>{item.content}</Text>
              </View>
            )
          })
        }
        </Headline>
      </View>
    )
  }
}

class Headline extends Component {
  static defaultProps = {
    bounces: true,
    infinite: false,
    autoplay: false,
    autoplayInterval: 3000,
    selectedIndex: 0,
  };

  static propTypes={
    itemHeight:PropTypes.number.isRequired
  }

  scrollviewRef;
  autoplayTimer;
  androidScrollEndTimer;
  scrollEndTimter;

  constructor (props) {
    super(props);
    const {children, selectedIndex} = this.props;
    const count = children ? children.length || 1 : 0;
    const index = count > 1 ? Math.min(selectedIndex, count - 1) : 0;
    this.state = {
      height: 0,
      isScrolling: false,
      autoplayEnd: false,
      loopJump: false,
      selectedIndex: index,
      offset: {x: 0, y: 0},
    };
  }

  componentDidMount () {
    const props = this.props;
    const count = props.children ? props.children.length || 1 : 0;
    const selectedIndex = count > 1 ? Math.min(props.selectedIndex, count - 1) : 0;
    const height = this.props.itemHeight;
    const offsetY = height * (selectedIndex + (props.infinite ? 1 : 0));
    this.setState({
      height,
      offset: {x: 0, y: offsetY},
    }, () => {
      if (Platform.OS === 'android') {
        this.scrollviewRef.scrollTo({y: offsetY, x: 0}, false);
      }
    });
    this.autoplay();
  }

  componentWillUnmount () {
    clearTimeout(this.autoplayTimer);
    clearTimeout(this.androidScrollEndTimer);
    clearTimeout(this.scrollEndTimter);
  }

  loopJump = () => {
    // iOS 通过 contentOffet 可以平滑过度，不需要做处理
    if (this.state.loopJump && Platform.OS === 'android') {
      const index = this.state.selectedIndex + (this.props.infinite ? 1 : 0);
      setTimeout(() => {
        const y = this.state.height * index;
        this.scrollviewRef.scrollTo({x:0, y: y}, false);
      }, 10);
    }
  }

  autoplay = () => {
    const {children, autoplay, infinite, autoplayInterval} = this.props;
    const {isScrolling, autoplayEnd, selectedIndex} = this.state;
    const count = children ? children.length || 1 : 0;
    if (!Array.isArray(children) || !autoplay || isScrolling || autoplayEnd) {
      return;
    }

    clearTimeout(this.autoplayTimer);

    this.autoplayTimer = setTimeout(() => {
      if (!infinite && (selectedIndex === count - 1)) {
        // !infinite && last one, autoplay end
        return this.setState({autoplayEnd: true});
      }
      this.scrollNextPage();
    }, autoplayInterval);
  }

  onScrollBegin = (e) => {
    this.setState({
      isScrolling: true,
    }, () => {
      if (this.props.onScrollBeginDrag) {
        this.props.onScrollBeginDrag(e, this.state, this);
      }
    });
  }

  onScrollEnd = (e) => {
    this.setState({isScrolling: false});
    // android incompatible
    if (!e.nativeEvent.contentOffset) {
      const position = e.nativeEvent.position;
      e.nativeEvent.contentOffset = {
        y: position * this.state.height,
      };
    }

    this.updateIndex(e.nativeEvent.contentOffset);

    this.scrollEndTimter = setTimeout(() => {
      this.autoplay();
      this.loopJump();
      if (this.props.onMomentumScrollEnd) {
        this.props.onMomentumScrollEnd(e, this.state, this);
      }
    });
  }



  updateIndex = (offset) => {
    let state = this.state;
    let selectedIndex = state.selectedIndex;
    let diff = offset.y - state.offset.y;
    let step = state.height;
    let loopJump = false;
    let count = this.props.children ? this.props.children.length || 1 : 0;

    // Do nothing if offset no change.
    if (!diff) {
      return;
    }

    selectedIndex = parseInt(selectedIndex + Math.round(diff / step), 10);

    if (this.props.infinite) {
      if (selectedIndex <= -1) {
        selectedIndex = count - 1;
        offset.y = step * count;
        loopJump = true;
      } else if (selectedIndex >= count) {
        selectedIndex = 0;
        offset.y = step;
        loopJump = true;
      }
    }

    this.setState({
      selectedIndex,
      offset,
      loopJump,
    });

    const {afterChange} = this.props;
    if (afterChange) {
      afterChange(selectedIndex);
    }
  }

  scrollNextPage = () => {
    const {children, infinite} = this.props;
    const count = children ? children.length || 1 : 0;
    if (this.state.isScrolling || count < 2) {
      return;
    }

    let state = this.state;
    let diff = (infinite ? 1 : 0) + this.state.selectedIndex + 1;
    let x = 0;
    let y = diff * state.height;

    this.scrollviewRef.scrollTo({x, y});

    this.setState({
      isScrolling: true,
      autoplayEnd: false,
    });

    // trigger onScrollEnd manually in android
    if (Platform.OS === 'android') {
      this.androidScrollEndTimer = setTimeout(() => {
        this.onScrollEnd({
          nativeEvent: {
            position: diff,
          },
        });
      }, 0);
    }
  }

  renderContent = (pages) => {
    const others = {
      onScrollBeginDrag: this.onScrollBegin,
      onMomentumScrollEnd: this.onScrollEnd,
    };
    return (
      <ScrollView
        ref={el => this.scrollviewRef = el}
        {...this.props}
        horizontal={false}
        pagingEnabled
        bounces={!!this.props.bounces}
        scrollEventThrottle={100}
        removeClippedSubviews={false}
        automaticallyAdjustContentInsets={false}
        directionalLockEnabled
        showsHorizontalScrollIndicator={false}
        showsVerticalScrollIndicator={false}
        contentContainerStyle={this.props.style}
        contentOffset={this.state.offset}
        {...others}
      >
        {pages}
      </ScrollView>
    );
  }


  render () {
    let state = this.state;
    let {infinite, children,itemHeight} = this.props;
    let pages: any = [];

    if (!children) {
      return (
        <Text style={{backgroundColor: 'white'}}>
          You are supposed to add children inside Carousel
        </Text>
      );
    }

    const pageStyle = {height: state.height};
    const count = children ? children.length || 1 : 0;
    // For make infinite at least count > 1
    if (count > 1) {
      pages = Object.keys(children);
      if (infinite) {
        pages.unshift(count - 1 + '');
        pages.push('0');
      }
      pages = pages.map((page, i) => {
        return (<View style={pageStyle} key={i}>{children[page]}</View>);
      });
    } else {
      pages = (<View style={pageStyle}>{children}</View>);
    }

    return (
      <View style={{height:itemHeight,overflow: 'hidden'}} >
        {this.renderContent(pages)}
      </View>
    );
  }
}

